home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
TPUG - Toronto PET Users Group
/
TPUG Users Group CD
/
TPUG Users Group CD.iso
/
AMIGA
/
AMICUS
/
AMICUS13.ADF
/
Gravity
/
gravity.c
< prev
next >
Wrap
C/C++ Source or Header
|
1986-08-05
|
18KB
|
733 lines
/*
* Gravity V2.2 June 17, 1986
*
* This program simulates planets in orbit around a star.
* See "Computer Recreations"
* SCIENTIFIC AMERICAN, January 1986.
*
* Data file format:
*
* (The (0,0) point is at the center of the screen.)
* Input format (all float values) :
* Gravitation Constant, Time Step, Display Scale
* Mass Star
* X Pos P1, Y Pos P1, X Vel P1, Y Vel P1, Mass P1
* X Pos P2, Y Pos P2, X Vel P2, Y Vel P2, Mass P2
* X Pos P3, Y Pos P3, X Vel P3, Y Vel P3, Mass P3
* . . .
*
*
* Author:
* Peter A. Giancola CompuServ ID: 76337,2542
* 8005 Mandan Road #101
* Greenbelt, Maryland 20770-2156
*
* Copyright (c) 1986 by Peter A. Giancola
* Permission is granted for unrestricted non-commercial use.
*
*
*/
/*
* Include all the system defs.
*/
#include "exec/types.h"
#include "exec/libraries.h"
#include "graphics/gfxbase.h"
#include "graphics/text.h"
#include "intuition/intuition.h"
#include "intuition/intuitionbase.h"
#include "lattice/math.h"
#include "lattice/stdio.h"
/*
* External math functions
*/
extern int SPTst();
extern int SPAbs();
extern int SPSqrt();
extern int SPAdd();
extern int SPSub();
extern int SPMul();
extern int SPDiv();
extern int SPPow();
extern int SPFieee();
extern float SPTieee();
/*
* Declare global variables.
*/
FILE *DataFile;
UBYTE FileName[32] = "GRAVITY.DAT";
int running = FALSE;
int saverunning = FALSE;
int title = TRUE;
int req = FALSE;
int zero;
int one;
int minus_one;
int two;
int one_hundred;
int minus_one_hundred;
int three_twenty;
int posx[7]; /* current X positions */
int posy[7]; /* current Y positions */
int velx[7]; /* current X velocities */
int vely[7]; /* current Y velocities */
int mass[7]; /* mass of planets */
int gmprod[7][7]; /* (G * m1 * m2) product matrix */
int prevx[7]; /* previous X positions */
int prevy[7]; /* previous Y positions */
int tstep; /* magnitude of time step for each update */
int gcons; /* gravitation constant */
int scale; /* scale of display screen */
int numplanets; /* number of planets in system */
USHORT menu_num_hide_t = (1 | (0 << 5));
USHORT menu_num_show_t = (1 | (1 << 5));
USHORT menu_num_go = (1 | (2 << 5));
USHORT menu_num_stop = (1 | (3 << 5));
/*
* Define library and Intuition pointers.
*/
struct GfxBase *GfxBase;
struct IntuitionBase *IntuitionBase;
struct RastPort *RastPort;
struct RastPort *AuthorRastPort;
struct ViewPort *ViewPort;
struct Window *Window;
struct Window *AuthorWindow;
struct Screen *Screen;
struct IntuiMessage *Message;
char *MathBase;
char *MathTransBase;
/*
* Define screen, window, menu and items.
*/
struct TextAttr Font =
{"topax.font", 8, 0, 0};
struct NewScreen NewScreen =
{0, 0, 640, 200, 4, 0, 1, HIRES, CUSTOMSCREEN, &Font,
" Gravity V2.2 ", 0, 0};
struct NewWindow NewWindow =
{0, 0, 640, 200, -1, -1, REQCLEAR|MENUPICK, BACKDROP|BORDERLESS|ACTIVATE,
0, 0, 0, 0, 0, 0, 0, 0, 0, CUSTOMSCREEN};
struct NewWindow NewAuthorWindow =
{100, 50, 500, 85, -1, -1, CLOSEWINDOW, WINDOWDRAG|WINDOWCLOSE|ACTIVATE,
0, 0, " Author ", 0, 0, 0, 0, 0, 0, CUSTOMSCREEN};
struct StringInfo FileNameString =
{FileName, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0};
struct Gadget FileNameGadget =
{0, 10, 15, 260, 10, GADGHCOMP, ENDGADGET, STRGADGET|REQGADGET,
0, 0, 0, 0, (APTR)&FileNameString, 0, 0};
struct IntuiText FileNameText =
{0, 0, JAM1, 65, 1, 0, "Enter file name", 0};
struct Requester FileNameRequester =
{0, 50, 50, 280, 30, 0, 0, &FileNameGadget, 0, &FileNameText, 0,
8, 0, 0, 0, 0};
struct IntuiText AuthorText[6] =
{
{3, 0, JAM2, 5, 15, 0,
"Peter A. Giancola", &AuthorText[1]},
{3, 0, JAM2, 5, 25, 0,
"8005 Mandan Road #101", &AuthorText[2]},
{3, 0, JAM2, 5, 35, 0,
"Greenbelt, Maryland 20770-2156", &AuthorText[3]},
{5, 0, JAM2, 270, 15, 0,
"CompuServ ID: 76337,2542", &AuthorText[4]},
{4, 0, JAM2, 5, 60, 0,
"Copyright (c) 1986 by Peter A. Giancola", &AuthorText[5]},
{4, 0, JAM2, 5, 70, 0,
"Permission is granted for unrestricted non-commercial use.", 0}
};
struct IntuiText MenuItemText[3][5] =
{
{
{0, 1, JAM2, 0, 0, 0, "Load ", 0},
{0, 1, JAM2, 0, 0, 0, "Save ", 0},
{0, 1, JAM2, 0, 0, 0, "Edit ", 0},
{0, 1, JAM2, 0, 0, 0, "Quit ", 0},
{0, 0, 0, 0, 0, 0, 0, 0}
},
{
{0, 1, JAM2, 0, 0, 0, "Hide Title", 0},
{0, 1, JAM2, 0, 0, 0, "Show Title", 0},
{0, 1, JAM2, 0, 0, 0, "Go ", 0},
{0, 1, JAM2, 0, 0, 0, "Stop ", 0},
{0, 1, JAM2, 0, 0, 0, "Restart ", 0}
},
{
{0, 1, JAM2, 0, 0, 0, "Author", 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0}
}
};
struct MenuItem MenuItem[3][5] =
{
{
{&MenuItem[0][1], 0, 0, 80, 10, ITEMTEXT|ITEMENABLED|HIGHBOX,
0, (APTR)&MenuItemText[0][0], 0, 0, 0, 0},
{&MenuItem[0][2], 0, 10, 80, 10, ITEMTEXT|HIGHBOX,
0, (APTR)&MenuItemText[0][1], 0, 0, 0, 0},
{&MenuItem[0][3], 0, 20, 80, 10, ITEMTEXT|HIGHBOX,
0, (APTR)&MenuItemText[0][2], 0, 0, 0, 0},
{0, 0, 30, 80, 10, ITEMTEXT|ITEMENABLED|HIGHBOX,
0, (APTR)&MenuItemText[0][3], 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
},
{
{&MenuItem[1][1], 0, 0, 90, 10, ITEMTEXT|ITEMENABLED|HIGHBOX,
0, (APTR)&MenuItemText[1][0], 0, 0, 0, 0},
{&MenuItem[1][2], 0, 10, 90, 10, ITEMTEXT|HIGHBOX,
0, (APTR)&MenuItemText[1][1], 0, 0, 0, 0},
{&MenuItem[1][3], 0, 20, 90, 10, ITEMTEXT|ITEMENABLED|HIGHBOX,
0, (APTR)&MenuItemText[1][2], 0, 0, 0, 0},
{&MenuItem[1][4], 0, 30, 90, 10, ITEMTEXT|HIGHBOX,
0, (APTR)&MenuItemText[1][3], 0, 0, 0, 0},
{0, 0, 40, 90, 10, ITEMTEXT|ITEMENABLED|HIGHBOX,
0, (APTR)&MenuItemText[1][4], 0, 0, 0, 0}
},
{
{0, 0, 0, 60, 10, ITEMTEXT|ITEMENABLED|HIGHBOX,
0, (APTR)&MenuItemText[2][0], 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
},
};
struct Menu Menu[3] =
{
{&Menu[1], 0, 0, 80, 10, MENUENABLED, "Projects", &MenuItem[0][0]},
{&Menu[2], 85, 0, 70, 10, MENUENABLED, "Control", &MenuItem[1][0]},
{0, 160, 0, 60, 10, MENUENABLED, "Author", &MenuItem[2][0]}
};
/*
* G r a v i t y
*/
main ()
{
/* Initialize library and Intuition pointers */
AuthorWindow = 0;
Window = 0;
Screen = 0;
IntuitionBase = 0;
GfxBase = 0;
/* Initialize the system */
dolibs(); /* Open the libraries */
zero = to_ffp(0.0);
one = to_ffp(1.0);
minus_one = to_ffp(-1.0);
two = to_ffp(2.0);
one_hundred = to_ffp(100.0);
minus_one_hundred = to_ffp(-100.0);
three_twenty = to_ffp(320.0);
doscreen(); /* Set up the screen and window */
doplanets(); /* Initialize the planets */
/* Begin running the simulation 'till the universe collapses... */
FOREVER
{
domsg(); /* Process any system messages */
if (running) docycle(); /* Update the planets */
};
}
/*
* Open the libraries
*/
dolibs ()
{
GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0);
if (GfxBase == 0) quit();
IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",
0);
if (IntuitionBase == 0) quit();
MathBase = (char *)OpenLibrary("mathffp.library", 0);
if (MathBase == 0) quit();
MathTransBase = (char *)OpenLibrary("mathtrans.library", 0);
if (MathTransBase == 0) quit();
}
/*
* Set up the screen and window
*/
doscreen ()
{
Screen = (struct Screen *)OpenScreen(&NewScreen);
if (Screen == 0) quit();
NewWindow.Screen = Screen;
NewAuthorWindow.Screen = Screen;
Window = (struct Window *)OpenWindow(&NewWindow);
if (Window == 0) quit();
ViewPort = &Screen->ViewPort;
RastPort = Window->RPort;
SetMenuStrip(Window, &Menu[0]);
if (title != TRUE)
{
OffMenu(Window,menu_num_hide_t);
OnMenu(Window,menu_num_show_t);
ShowTitle(Screen,FALSE);
};
SetRGB4(ViewPort, 0, 00, 00, 00);
SetRGB4(ViewPort, 1, 13, 13, 13);
SetRGB4(ViewPort, 2, 00, 00, 13);
SetRGB4(ViewPort, 3, 15, 15, 00);
SetRGB4(ViewPort, 4, 15, 00, 00);
SetRGB4(ViewPort, 5, 00, 15, 00);
SetRGB4(ViewPort, 6, 00, 00, 15);
SetRGB4(ViewPort, 7, 00, 15, 15);
SetRGB4(ViewPort, 8, 09, 09, 09);
SetRGB4(ViewPort, 9, 06, 00, 00);
SetRGB4(ViewPort, 10, 08, 08, 00);
SetRGB4(ViewPort, 11, 08, 00, 00);
SetRGB4(ViewPort, 12, 00, 08, 00);
SetRGB4(ViewPort, 13, 00, 00, 08);
SetRGB4(ViewPort, 14, 00, 08, 08);
SetRGB4(ViewPort, 15, 10, 10, 00);
}
/*
* Clean up and exit
*/
quit ()
{
if (AuthorWindow)
{
running = saverunning;
SetMenuStrip(Window, &Menu[0]);
CloseWindow(AuthorWindow);
AuthorWindow = 0;
AuthorRastPort = 0;
};
/*
if (FileNameWindow)
{
running = saverunning;
SetMenuStrip(Window, &Menu[0]);
CloseWindow(FileNameWindow);
FileNameWindow = 0;
};
*/
if (Window)
{
ClearMenuStrip(Window);
CloseWindow(Window);
};
if (Screen) CloseScreen(Screen);
if (MathTransBase) CloseLibrary(MathTransBase);
if (MathBase) CloseLibrary(MathBase);
if (IntuitionBase) CloseLibrary(IntuitionBase);
if (GfxBase) CloseLibrary(GfxBase);
exit();
}
/*
* Kill screen for restart
*/
killscreen ()
{
if (AuthorWindow)
{
running = saverunning;
SetMenuStrip(Window, &Menu[0]);
CloseWindow(AuthorWindow);
AuthorWindow = 0;
AuthorRastPort = 0;
};
if (Window)
{
SetRast(RastPort,0);
};
}
/*
* Process system messages
*/
domsg ()
{
ULONG class;
USHORT code;
USHORT menunum;
USHORT itemnum;
int mousex;
int mousey;
/* If the author window is open, look for close window messages
from it */
if (AuthorWindow != 0)
{
Message = (struct IntuiMessage *)GetMsg(AuthorWindow->UserPort);
if (Message != 0)
{
class = Message->Class;
ReplyMsg(Message);
if (class == CLOSEWINDOW)
{
running = saverunning;
CloseWindow(AuthorWindow);
AuthorWindow = 0;
AuthorRastPort = 0;
SetMenuStrip(Window, &Menu[0]);
};
};
};
/* Now look for menu selection messages */
Message = (struct IntuiMessage *)GetMsg(Window->UserPort);
if (Message != 0)
{
class = Message->Class;
code = Message->Code;
mousex = Window->MouseX;
mousey = Window->MouseY;
ReplyMsg(Message);
if (class == REQCLEAR)
{
killscreen();
doplanets();
SetMenuStrip(Window, &Menu[0]);
OffMenu(Window,menu_num_go);
OnMenu(Window,menu_num_stop);
running = saverunning;
};
if (class == MENUPICK && code != MENUNULL)
{
menunum = MENUNUM(code);
itemnum = ITEMNUM(code);
switch (menunum)
{
case 0:
/* Projects */
switch (itemnum)
{
case 0:
/* Load */
ClearMenuStrip(Window);
saverunning = TRUE;
running = FALSE;
Request(FileNameRequester, Window);
break;
case 1:
/* Save */
break;
case 2:
/* Edit */
break;
case 3:
/* Quit */
quit();
break;
};
break;
case 1:
/* Control */
switch (itemnum)
{
case 0:
/* Hide Title */
menu_num_hide_t = code;
OffMenu(Window,code);
OnMenu(Window,menu_num_show_t);
ShowTitle(Screen,FALSE);
title = FALSE;
break;
case 1:
/* Show Title */
ShowTitle(Screen,TRUE);
menu_num_show_t = code;
OffMenu(Window,code);
OnMenu(Window,menu_num_hide_t);
title = TRUE;
break;
case 2:
/* Go */
menu_num_go = code;
OffMenu(Window,code);
OnMenu(Window,menu_num_stop);
running = TRUE;
break;
case 3:
/* Stop */
menu_num_stop = code;
OffMenu(Window,code);
OnMenu(Window,menu_num_go);
running = FALSE;
break;
case 4:
/* Restart */
killscreen();
doplanets();
break;
};
break;
case 2:
/* Author */
ClearMenuStrip(Window);
saverunning = running;
running = FALSE;
AuthorWindow = (struct Window *)OpenWindow(&NewAuthorWindow);
if (AuthorWindow == 0) quit();
AuthorRastPort = AuthorWindow->RPort;
PrintIText(AuthorRastPort,&AuthorText[0],0,0);
break;
};
};
};
}
/*
* Update the planets
*/
docycle ()
{
int tmp;
int tmp2;
int i;
int j;
int dx;
int dy;
int dist;
int force;
int forx;
int fory;
int scrx;
int scry;
/* Make one pass for each planet in the system */
for (i = 1; i < numplanets; ++i)
{
/* Accumulate the forces on the current planet due to
all the other planets */
forx = zero;
fory = zero;
for (j = 0; j < numplanets; ++j)
{
if (j != i)
{
/* Calculate the distance between the two selected planets */
dx = SPSub (posx[i], posx[j]);
dy = SPSub (posy[i], posy[j]);
dist = SPSqrt(SPAdd(SPPow(two,dx),SPPow(two,dy)));
tmp = SPSub (dist, one);
if (! SPTst (SPSub (tmp, SPAbs(tmp)))) dist = one;
/* Now calculate the force due to gravity using the G cons *
M1 * M2 product matrix to speed the calculation. */
force = SPDiv(SPMul(dist, dist), gmprod[i][j]);
/* The force is a vector, so split it into components. */
forx = SPAdd(forx,SPDiv(dist,SPMul(force,dx)));
fory = SPAdd(fory,SPDiv(dist,SPMul(force,dy)));
};
};
/* Use the force vector to calculate the planet's new velocity. */
velx[i] = SPAdd(velx[i], SPMul(SPDiv(mass[i], forx), tstep));
vely[i] = SPAdd(vely[i], SPMul(SPDiv(mass[i], fory), tstep));
};
/* Now update the positions of all planets using the accumulated
velocity. The new positions are scaled and limited to the screen
boundries. */
for (i = 0; i < numplanets; ++i)
{
/* Update the X position */
posx[i] = SPAdd(posx[i],SPMul(velx[i],tstep));
tmp = SPSub (one_hundred, posx[i]);
tmp2 = SPSub (posx[i], minus_one_hundred);
if ((! SPTst (SPSub (tmp, SPAbs(tmp)))) ||
(! SPTst (SPSub (tmp2, SPAbs(tmp2)))))
{
velx[i] = zero;
vely[i] = zero;
};
scrx = (int) (SPTieee(SPAdd(SPMul(SPMul(two,scale),posx[i]),
three_twenty)));
if (scrx < 0) scrx = 0;
if (scrx > 639) scrx = 639;
/* Update the Y position */
posy[i] = SPAdd(posy[i],SPMul(vely[i],tstep));
tmp = SPSub (one_hundred, posy[i]);
tmp2 = SPSub (posy[i], minus_one_hundred);
if ((! SPTst (SPSub (tmp, SPAbs(tmp)))) ||
(! SPTst (SPSub (tmp2, SPAbs(tmp2)))))
{
velx[i] = zero;
vely[i] = zero;
};
scry = (int) (SPTieee(SPAdd(SPMul(SPMul(scale,minus_one),posy[i]),
one_hundred)));
if (scry < 0) scry = 0;
if (scry > 199) scry = 199;
/* Now use the saved previous screen position to leave a trail. */
SetAPen(RastPort,(i + 10));
j = WritePixel(RastPort, prevx[i], prevy[i]);
/* Draw the new position and save it as the previous position. */
SetAPen(RastPort,(i + 3));
j = WritePixel(RastPort, scrx, scry);
prevx[i] = scrx;
prevy[i] = scry;
};
}
/*
* Read the initial conditions.
*/
doplanets ()
{
int i;
int j;
int scrx;
int scry;
float gc;
float x[4];
float m[7];
OffMenu(Window,menu_num_stop);
OnMenu(Window,menu_num_go);
running = FALSE;
DataFile = fopen(FileName, "r");
if (DataFile != NULL)
{
j = fscanf(DataFile, "%f %f %f", &gc, &x[0], &x[1]);
gcons = to_ffp(gc);
tstep = to_ffp(x[0]);
scale = to_ffp(x[1]);
i = 0;
/* Read the star's mass first. */
j = fscanf(DataFile, "%f", &m[i]);
mass[i] = to_ffp(m[i]);
posx[i] = zero;
posy[i] = zero;
velx[i] = zero;
vely[i] = zero;
/* Now read the planet's parameters. */
while (j != EOF && i < 5)
{
i += 1;
j = fscanf(DataFile, "%f %f %f %f %f",
&x[0], &x[1], &x[2], &x[3], &m[i]);
posx[i] = to_ffp(x[0]);
posy[i] = to_ffp(x[1]);
velx[i] = to_ffp(x[2]);
vely[i] = to_ffp(x[3]);
mass[i] = to_ffp(m[i]);
};
numplanets = i;
i = fclose(DataFile);
/* Initialize the G cons * M1 * M2 product matrix. */
for (i = 0; i < numplanets; ++i)
{
scrx = (int) (SPTieee(SPAdd(SPMul(SPMul(two,scale),posx[i]),
three_twenty)));
if (scrx < 0) scrx = 0;
if (scrx > 639) scrx = 639;
scry = (int) (SPTieee(SPAdd(SPMul(SPMul(scale,minus_one),posy[i]),
one_hundred)));
if (scry < 0) scry = 0;
if (scry > 199) scry = 199;
prevx[i] = scrx;
prevy[i] = scry;
for (j = 0; j < numplanets; ++j)
{
if (i != j) gmprod[i][j] = to_ffp(gc * m[i] * m[j]);
else gmprod[i][j] = zero;
};
};
OffMenu(Window, menu_num_go);
OnMenu(Window, menu_num_stop);
running = TRUE;
};
}
/*
* convert from Lattice float to FFP.
*/
int to_ffp (arg)
double arg;
{
union
{
int i;
float r;
} temp;
temp.r = arg;
return (SPFieee(temp.i));
}